﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Modules.Audit.Repositories;
using Modules.System.Flow;
using PmSoft;
using PmSoft.ApplicationContext;
using PmSoft.Exceptions;
using static Modules.Audit.SysAuditLogConstants;
using static Modules.System.Flow.FlowConstants;

namespace Modules.Audit
{
    [UseDI(ServiceLifetime.Scoped)]
    public class SysAuditLogService
    {
        private readonly SysAuditLogRepository sysAuditLogRepository;
        private readonly SysFlowService flowService;
        private readonly SysFlowEngineService flowEngineService;
        private readonly IApplicationContext applicationContext;
        private readonly ILogger logger;

        public SysAuditLogService(SysAuditLogRepository sysAuditLogRepository,
            SysFlowService flowService,
            SysFlowEngineService flowEngineService,
            IApplicationContext applicationContext,
              ILogger<SysAuditLogService> logger
            )
        {
            this.sysAuditLogRepository = sysAuditLogRepository;
            this.flowService = flowService;
            this.flowEngineService = flowEngineService;
            this.applicationContext = applicationContext;
            this.logger = logger;
        }

        public IEnumerable<SysAuditLog> GetSysAuditLogs(int objectId, string tableName)
        {
            return sysAuditLogRepository.GetAuditLogsByObjectId(objectId, tableName);
        }

        /// <summary>
        /// 审核
        /// </summary>
        /// <param name="flowEngineCode">当前审核步骤</param>
        /// <param name="auditForm">审核信息</param>
        /// <param name="personFlowEngine">登录人员审核步骤</param>
        /// <exception cref="BusinessException"></exception>
        public FlowEngine? Audit(out bool isFirst, FlowEngine flowEngineCode, SysAuditLog auditForm, FlowEngine personFlowEngine)
        {
            isFirst = false;
            FlowEngine? flowEngine = null;
            if (flowEngineCode != personFlowEngine)
                throw new BusinessException($"当前信息您暂时不能审核");
            //查询最后一条审核记录
            SysAuditLog? sysAuditLog = sysAuditLogRepository.GetLastSysAuditLogByTableAndObjectId(auditForm.TableName, auditForm.ObjectId);
            if (sysAuditLog == null)
                throw new BusinessException($"当前数据没有提交审核记录,请先提交审核");
            SysFlowEngine? sysFlowEngine = flowEngineService.GetFlowEngineByFlowEngineCode(sysAuditLog.FlowId, sysAuditLog.FlowEngineCode);
            if (sysFlowEngine == null)
                throw new BusinessException($"当前流程步骤不存在,请联系管理员");
            if (flowEngineCode != sysFlowEngine.Code)
                throw new BusinessException($"当前信息您暂时不能审核");
            sysAuditLog.AuditStatus = AuditStatus.已审核;
            sysAuditLog.AuditIdea = auditForm.AuditIdea;
            sysAuditLog.AuditIdeaContent = auditForm.AuditIdeaContent;
            sysAuditLog.AuditUserId = applicationContext.CurrentUser?.Id ?? 0;
            sysAuditLog.AuditTime = DateTime.Now;
            sysAuditLog.AuditUserName = applicationContext.CurrentUser?.Name ?? "";

            if (auditForm.AuditIdea == AuditIdea.同意)
            {
                var next = flowEngineService.GetNextFlowEngine(sysAuditLog.FlowId, sysAuditLog.FlowEngineCode);
                if (next == null) throw new BusinessException($"当前流程步骤没有结束步骤，请联系管理员重新配置");
                //新增下一步骤
                SysAuditLog sysAuditNext = new SysAuditLog()
                {
                    FlowId = sysAuditLog.FlowId,
                    FlowEngineCode = next.Code,
                    ObjectId = sysAuditLog.ObjectId,
                    TableName = sysAuditLog.TableName,
                    AuditStatus = AuditStatus.待审核,
                    CreateTime = DateTime.Now,
                    CreateUserId = applicationContext.CurrentUser?.Id ?? 0,
                    CreateUserName = applicationContext.CurrentUser?.Name ?? "",
                    Sort = sysAuditLog.Sort + 1
                };
                //判断下一步骤是否是最后一步
                if (next.Code == FlowEngine.结束)
                    sysAuditNext.AuditStatus = AuditStatus.已审核;

                sysAuditLogRepository.Insert(sysAuditNext);
                flowEngine = next.Code;
            }
            else if (auditForm.AuditIdea == AuditIdea.不同意)
            {
                if (string.IsNullOrWhiteSpace(auditForm.AuditIdeaContent))
                {
                    throw new BusinessException($"审核意见为不同意时,原因必填");
                }
                //退回
                SysAuditLog sysAuditNext = new SysAuditLog()
                {
                    FlowId = sysAuditLog.FlowId,
                    ObjectId = sysAuditLog.ObjectId,
                    TableName = sysAuditLog.TableName,
                    AuditStatus = AuditStatus.待审核,
                    CreateTime = DateTime.Now,
                    CreateUserId = applicationContext.CurrentUser?.Id ?? 0,
                    CreateUserName = applicationContext.CurrentUser?.Name ?? "",
                    Sort = sysAuditLog.Sort + 1
                };

                if (!sysFlowEngine.SendBackCode.HasValue)
                {
                    //新增上一步骤
                    SysFlowEngine? previous = flowEngineService.GetPreviousFlowEngine(sysAuditLog.FlowId, sysAuditLog.FlowEngineCode);
                    sysAuditNext.FlowEngineCode = previous?.Code ?? 0;
                    flowEngine = previous.Code;
                    //判断指定步骤是否等于第一步
                    SysFlowEngine? first = flowEngineService.GetFirstFlowEngine(sysAuditLog.FlowId);
                    if (previous.Id == first?.Id)
                    {
                        sysAuditNext.AuditStatus = AuditStatus.待提交;
                        isFirst = true;
                    }
                }
                else
                {
                    //新增指定步骤
                    var SysFlowEngines = flowEngineService.GetSysFlowEngineByFlowId(sysAuditLog.FlowId);
                    SysFlowEngine? appoint = new SysFlowEngine();
                    if (SysFlowEngines.Count() > 0)
                    {
                        appoint = SysFlowEngines.Where(a => a.Code == sysFlowEngine.SendBackCode).FirstOrDefault();
                    }
                    sysAuditNext.FlowEngineCode = appoint?.Code ?? 0;
                    flowEngine = appoint.Code;
                    //判断指定步骤是否等于第一步
                    var first = flowEngineService.GetFirstFlowEngine(sysAuditLog.FlowId);
                    if (appoint.Id == first.Id)
                    {
                        sysAuditNext.AuditStatus = AuditStatus.待提交;
                        isFirst = true;
                    }
                }
                sysAuditLogRepository.Insert(sysAuditNext);
            }
            sysAuditLogRepository.Update(sysAuditLog);

            return flowEngine;
        }

        /// <summary>
        /// 提交审批
        /// </summary>
        /// <param name="objectId">主表id</param>
        /// <param name="flowCode">流程编码</param>
        /// <param name="tableName">业务表名</param>
        public FlowEngine SubmitAuditLog(int objectId, string flowCode, string tableName)
        {
            //根据流程编码查询流程数据
            SysFlow? sysFlow = flowService.GetFlowByCode(flowCode);
            if (sysFlow == null)
                throw new BusinessException($"流程编码:{flowCode}不存在");
            //判断审核记录表是否有数据
            var sysAuditLogs = GetAuditLogsByObjectId(objectId, tableName);
            if (sysAuditLogs.Count() == 0)
            {
                //新增第一步骤

                var flowEngine = flowEngineService.GetFirstFlowEngine(sysFlow.Id);
                if (flowEngine == null)
                    throw new BusinessException($"流程编码:{flowCode}不存在步骤");
                SysAuditLog sysAuditLog = new SysAuditLog()
                {
                    FlowId = sysFlow.Id,
                    FlowEngineCode = flowEngine.Code,
                    ObjectId = objectId,
                    TableName = tableName,
                    AuditStatus = AuditStatus.待提交,
                    CreateTime = DateTime.Now,
                    CreateUserId = applicationContext.CurrentUser?.Id ?? 0,
                    CreateUserName = applicationContext.CurrentUser?.Name ?? "",
                    Sort = 1
                };
                sysAuditLogRepository.Insert(sysAuditLog);

                //新增第二步
                flowEngine = flowEngineService.GetNextFlowEngine(flowEngine.FlowId, flowEngine.Code);
                sysAuditLog = new SysAuditLog()
                {
                    FlowId = sysFlow.Id,
                    FlowEngineCode = flowEngine.Code,
                    ObjectId = objectId,
                    TableName = tableName,
                    AuditStatus = AuditStatus.待审核,
                    CreateTime = DateTime.Now,
                    CreateUserId = applicationContext.CurrentUser?.Id ?? 0,
                    CreateUserName = applicationContext.CurrentUser?.Name ?? "",
                    Sort = sysAuditLog.Sort + 1
                };
                sysAuditLogRepository.Insert(sysAuditLog);
                return flowEngine.Code;
            }
            else
            {
                SysAuditLog? last = sysAuditLogs.OrderByDescending(a => a.Sort).FirstOrDefault();
                //新增下一步
                var flowEngine = flowEngineService.GetNextFlowEngine(sysFlow.Id, last.FlowEngineCode);
                SysAuditLog sysAuditLog = new SysAuditLog()
                {
                    FlowId = sysFlow.Id,
                    FlowEngineCode = flowEngine.Code,
                    ObjectId = objectId,
                    TableName = tableName,
                    AuditStatus = AuditStatus.待审核,
                    CreateTime = DateTime.Now,
                    CreateUserId = applicationContext.CurrentUser?.Id ?? 0,
                    CreateUserName = applicationContext.CurrentUser?.Name ?? "",
                    Sort = last.Sort + 1
                };
                sysAuditLogRepository.Insert(sysAuditLog);
                return flowEngine.Code;
            }
        }

        /// <summary>
        /// 根据主表id和主表名称查询日志集合
        /// </summary>
        /// <param name="objectId"></param>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public IEnumerable<SysAuditLog> GetAuditLogsByObjectId(int objectId, string tableName)
        {
            return sysAuditLogRepository.GetAuditLogsByObjectId(objectId, tableName);
        }
    }
}